#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<errno.h>
#include<string.h>
#include<sys/stat.h>
#include<assert.h>
#include<unistd.h>

using namespace std;

#define PATHNAME "./"
#define PROJID 0664
#define SIZE 4096

key_t GetKey()
{
  key_t key = ftok(PATHNAME,PROJID);
  if(key == -1)
  {
    cout << "GetKey happen error , errno : " << errno << " strerror(errno)" << endl; 
    exit(1);
  }

  return key;
}

int ShmGetHelper(key_t key,int Size,int shmflg)
{
  int n = shmget(key,Size,shmflg);
  if(n == -1) 
  {
    cout << "ShmGet happen error , errno : " << errno << " strerror(errno)" << endl; 
    exit(2);
  }
  return n;
}

int creatShm(key_t key,int Size)
{
  umask(0);
  int n = ShmGetHelper(key,Size,IPC_CREAT | IPC_EXCL | PROJID);
  if(n < 0)
  {
    return -1;
  }
  return n;
}

int GetShm(key_t key,int Size)
{
  int n = ShmGetHelper(key,Size,IPC_CREAT);
  if(n < 0)
  {
    return -1;
  }

  return n;
}

char* AttachShm(int shmid)
{
  char* Start = (char*)shmat(shmid,nullptr,0);
  return Start;
}

void DetachShm(char* Start)
{
  int n = shmdt(Start);
  assert(n != -1);
  (void)n;
  return;
}

void DeleteShm(int shmid)
{
  int n = shmctl(shmid,IPC_RMID,nullptr);
  assert(n != -1);
  (void)n;
  return;
}

#define SERVER 0
#define CLIENT 1

class shm
{
public:
  shm(int type)
    :_type(type)
  {
    //获取key
    key_t key = GetKey();

    //根据不同对象，创建共享内存或者获取共享内存
    if(_type == SERVER) _shmid = creatShm(key,SIZE);
    else _shmid = GetShm(key,SIZE);
    
    //关联
    _Start = AttachShm(_shmid);
  }

  char* GetStart()
  {
    return _Start;
  }

  ~shm()
  {
    //去关联
    DetachShm(_Start);

    //根据不同对象，判断是否需要删除共享内存
    if(_type == SERVER) DeleteShm(_shmid);
  }
private:
  int _type;
  char* _Start;
  int _shmid;
};


